package com.tanger.auth.provider;

import com.tanger.auth.mapper.AuthMapper;
import com.tanger.common.redis.RedisUtil;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 短信验证码登录
 */
public class SmsTokenGranter extends AbstractTokenGranter {
   private final AuthMapper authMapper;
   private final RedisUtil redisUtils;
   private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

   public SmsTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                          OAuth2RequestFactory requestFactory, AuthMapper authMapper, RedisUtil redisUtils) {
      this(tokenServices, clientDetailsService, requestFactory, authMapper, redisUtils, "mobile");
   }

   protected SmsTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                             OAuth2RequestFactory requestFactory, AuthMapper authMapper, RedisUtil redisUtils, String grantType) {
      super(tokenServices, clientDetailsService, requestFactory, grantType);
      this.authMapper = authMapper;
      this.redisUtils = redisUtils;
   }

   protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
      Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
      String mobile = (String) parameters.get("mobile");
      String smsCaptcha =(String) parameters.get("smsCaptcha");
      //String roletype =(String) parameters.get("roletype");
      Authentication userAuth = null;
      try {
         LinkedHashMap<String, String> user = authMapper.getSysUserByMobile(mobile);

         if (user == null) {
            throw new UsernameNotFoundException(String.format("找不到此手机号%s。", mobile));
         }
         String smsCaptchaKey = "BASEOAUTH:CAPTCHA:MOBILE:" + mobile;
         String smsCaptchaCache = this.redisUtils.get(smsCaptchaKey).toString();
         if (!smsCaptcha.equals(smsCaptchaCache)) {
            throw new IllegalArgumentException("短信验证码错误或已过期，请重新输入。");
         }
         this.redisUtils.del(smsCaptchaKey);

         List<String> roleCodeList = new ArrayList();
         UserDetails userDetails = new User(user.get("name").toString(), user.get("password").toString(), AuthorityUtils.createAuthorityList(roleCodeList.toArray(new String[] {})));
         parameters.put("id", user.get("id").toString());
         parameters.put("name", user.get("name").toString());
         parameters.put("phone", user.get("mobile").toString());
         parameters.put("roleType", "");

         userAuth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
         ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
      } catch (AccountStatusException var16) {
         throw new InvalidGrantException(var16.toString());
      } catch (BadCredentialsException var17) {
         throw new InvalidGrantException(var17.toString());
      }

      if (!userAuth.isAuthenticated()) {
         throw new InvalidGrantException("Could not authenticate mobile: " + mobile);
      } else {
         OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
         return new OAuth2Authentication(storedOAuth2Request, userAuth);
      }
   }
}
